package crmdna.interaction;

import static crmdna.common.OfyService.ofy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.googlecode.objectify.Work;

import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;
import crmdna.common.Utils;
import crmdna.member.Member;
import crmdna.sequence.Sequence;
import crmdna.sequence.Sequence.SequenceType;
import crmdna.user.User;
import crmdna.user.User.Action;
import crmdna.user.User.ResourceType;
import crmdna.user.UserCore;

public class Interaction {

	public enum InteractionType {
		PHONE, EMAIL, FB, GOOGLEPLUS, SMS, FACETOFACE, WEBSITE, OTHER
	}

	private final static long MAX_INTERACTION_SIZE = 900 * 1024;

	static InteractionProp create(String client, long memberId,
			String interaction, InteractionType interactionType,
			Date timestamp, String login) {

		if (null == timestamp)
			timestamp = new Date();

		ensureValid(interaction, interactionType, timestamp);

		Member.safeGet(client, memberId, login);

		long userId = User.safeGet(client, login).toProp().userId;

		InteractionEntity interactionEntity = new InteractionEntity();
		interactionEntity.interactionId = Sequence.getNext(client,
				SequenceType.INTERACTION);

		interactionEntity.memberId = memberId;
		interactionEntity.timestamp = timestamp;
		interactionEntity.interaction = interaction;
		interactionEntity.interactionType = interactionType;
		interactionEntity.userId = userId;

		ofy(client).save().entity(interactionEntity).now();
		return interactionEntity.toProp();
	}

	private static void ensureValid(String interaction,
			InteractionType interactionType, Date timestamp) {

		if (null == interactionType)
			Utils.throwIncorrectSpecException("interactionType cannot be null");

		if ((null == interaction) || interaction.equals(""))
			Utils.throwIncorrectSpecException("interaction cannot be null or empty string");

		if (interaction.length() > MAX_INTERACTION_SIZE)
			Utils.throwIncorrectSpecException("interaction cannot be null or empty string");

		if (null == timestamp)
			Utils.throwIncorrectSpecException("timestamp cannot be null");
	}

	static void delete(String client, long interactionId, String login) {

		InteractionEntity interactionEntity = safeGet(client, interactionId,
				login);
		InteractionProp interactionProp = interactionEntity.toProp();

		// need privilege to delete interaction created by someone else
		long userId = UserCore.get(client, login).toProp().userId;

		if (userId != interactionProp.userId)
			crmdna.user.User.ensureAccess(client, login,
					ResourceType.INTERACTION, 0, Action.WRITE);

		ofy(client).delete().entity(interactionEntity).now();
	}

	static InteractionEntity safeGet(String client, long interactionId,
			String login) {

		User.ensureValidUser(client, login);

		InteractionEntity interactionEntity = ofy(client).load()
				.type(InteractionEntity.class).id(interactionId).get();

		if (null == interactionEntity)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST,
					"Interaction id [" + interactionId + "] does not exist");

		return interactionEntity;
	}

	static List<InteractionProp> get(String client,
			Iterable<Long> interactionIds, String login) {

		User.ensureValidUser(client, login);

		List<InteractionProp> props = new ArrayList<>();

		Map<Long, InteractionEntity> entities = ofy(client).load()
				.type(InteractionEntity.class).ids(interactionIds);

		for (InteractionEntity entity : entities.values()) {
			if (null != entity)
				props.add(entity.toProp());
		}

		Collections.sort(props);
		return props;
	}

	static List<InteractionProp> get(String client, long interactionId,
			String login) {
		List<Long> interactionIds = new ArrayList<>();
		interactionIds.add(interactionId);

		return get(client, interactionIds, login);
	}

	static InteractionProp update(final String client,
			final long interactionId, final String interaction,
			final InteractionType interactionType, Date timestamp,
			final String login) {

		User.ensureValidUser(client, login);

		InteractionProp interactionProp = safeGet(client, interactionId, login)
				.toProp();

		// need privilege to update interaction created by someone else
		final long userId = UserCore.get(client, login).toProp().userId;

		if (userId != interactionProp.userId)
			crmdna.user.User.ensureAccess(client, login,
					ResourceType.INTERACTION, 0, Action.WRITE);

		if (null == timestamp)
			timestamp = new Date();

		ensureValid(interaction, interactionType, timestamp);

		final Date ts = timestamp;
		interactionProp = ofy(client).transact(new Work<InteractionProp>() {

			@Override
			public InteractionProp run() {
				InteractionEntity interactionEntity = safeGet(client,
						interactionId, login);
				if (null != interaction)
					interactionEntity.interaction = interaction;

				if (null != interactionType)
					interactionEntity.interactionType = interactionType;

				interactionEntity.timestamp = ts;
				interactionEntity.userId = userId;

				ofy(client).save().entity(interactionEntity).now();
				return interactionEntity.toProp();
			}
		});

		return interactionProp;
	}
}
